import copy
import json
import os
import threading
from datetime import datetime
from json import JSONDecodeError
from time import sleep

import requests
from django.conf import settings
from django.shortcuts import render
from django.http import JsonResponse, HttpResponse
# Create your views here.
from django.views.decorators.csrf import csrf_exempt

from ApiAutoTestPlatform.settings import BASE_DIR
from apitests import models
from apitests.models import ApiDefine, ApiCase, ApiAutoTest, CaseTemporary
from common import config
from common.config import BASE_PATH
from common.pagination import Pagination
from common.read_sql import read_sql
from common.run_suite import run_suite
from common.threading_result import ThreadTimer
from projects.models import Projects, Modules
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger

from test_reports.models import TestReports
from users.models import UserProfile

CURRENT_PATH = settings.BASE_DIR + os.sep + 'apitests'


def api_define_list(request):
    try:
        page = request.GET.get('page', 1)
    except PageNotAnInteger:
        page = 1
    nums = request.GET.get('nums', None)
    search_text = request.GET.get('Search', '')
    search_dict = {}
    projects_list = Projects.objects.all().order_by('-create_time')
    is_project = int(request.COOKIES['Project'])
    if is_project:
        project_id = projects_list.get(id=is_project)
        modules_list = project_id.modules_set.all()
        modules_id_list = [modules.id for modules in modules_list]
        search_dict['module__in'] = modules_id_list
    if search_text:
        search_dict['name__contains'] = search_text
    api_defines_list = ApiDefine.objects.filter(**search_dict).order_by('-create_time')
    content = Pagination(api_defines_list, search_text, page, nums).per_page()
    content['projects_list'] = projects_list
    content['is_project'] = is_project
    return render(request, 'api_define_list.html', content)


def api_define_add(request):
    if request.method == 'GET':
        projects_list = Projects.objects.all().order_by('-create_time')
        is_project = int(request.COOKIES['Project'])
        project_id = projects_list.get(id=is_project)
        modules_list = project_id.modules_set.all()
        users = UserProfile.objects.all()
        api_defines_list = ApiDefine.objects.all()
        content = {
            'modules_list': modules_list,
            'users': users,
            'api_defines_list': api_defines_list,
            'projects_list': projects_list,
            'is_project': is_project,
        }
        return render(request, 'api_define_add.html', content)
    api_name = request.POST['api_name']
    api_module = request.POST['api_module']
    api_user = request.POST['api_user']
    api_status = request.POST['api_status']
    api_method = request.POST['api_method']
    api_url = request.POST['api_url']
    api_params = request.POST['api_params']
    api_headers = request.POST['api_headers']
    is_assert = request.POST['is_assert']
    body_choice = request.POST['body_choice']
    api_body = request.POST['api_body']
    assert_choice = request.POST['assert_choice']
    api_assert = request.POST['api_assert']
    api_describe = request.POST['api_describe']
    if (api_name and api_module and api_user and api_method and api_url):
        api_define = ApiDefine(name=api_name, module_id=api_module, interface=api_url, tester_id=api_user,
                               status=api_status, method=api_method, params=api_params, headers=api_headers,
                               body_type=body_choice, body=api_body, assert_type=assert_choice, assert_body=api_assert,
                               describe=api_describe, is_assert=is_assert)
        api_define.save()
        return JsonResponse({"status": True})

    return JsonResponse({"status": False, "error_msg": "信息未填写完整"})


def api_define_del(request):
    api_define_id = request.POST['api_define_id']
    ApiDefine.objects.filter(id=api_define_id).delete()
    return JsonResponse({"status": True})


def api_define_edit(request):
    if request.method == 'GET':
        projects_list = Projects.objects.all().order_by('-create_time')
        is_project = int(request.COOKIES['Project'])
        api_define_id = request.GET.get('api_define_id')
        api_define = ApiDefine.objects.get(id=api_define_id)
        project_id = Modules.objects.get(id=api_define.module_id).project_id
        modules = Projects.objects.get(id=project_id).modules_set.all()
        users = UserProfile.objects.all()
        params = json.loads(api_define.params)
        headers = json.loads(api_define.headers)
        body = json.loads(api_define.body)
        content = {
            'api_define': api_define,
            'users': users,
            "modules": modules,
            "params": params,
            "headers": headers,
            "body": body,
            "projects_list": projects_list,
            "is_project": is_project,
        }
        return render(request, 'api_define_edit.html', content)
    is_assert = request.POST['is_assert']
    api_id = request.POST['api_id']
    api_name = request.POST['api_name']
    api_module = request.POST['api_module']
    api_user = request.POST['api_user']
    api_status = request.POST['api_status']
    api_method = request.POST['api_method']
    api_url = request.POST['api_url']
    api_params = request.POST['api_params']
    api_headers = request.POST['api_headers']
    body_choice = request.POST['body_choice']
    api_body = request.POST['api_body']
    assert_choice = request.POST['assert_choice']
    api_assert = request.POST['api_assert']
    api_describe = request.POST['api_describe']
    if (api_name and api_module and api_user and api_method and api_url):
        ApiDefine.objects.filter(id=api_id).update(name=api_name, module_id=api_module, interface=api_url,
                                                   tester_id=api_user,
                                                   status=api_status, method=api_method, params=api_params,
                                                   headers=api_headers,
                                                   body_type=body_choice, body=api_body,
                                                   assert_type=assert_choice, assert_body=api_assert,
                                                   describe=api_describe, is_assert=is_assert)
        return JsonResponse({"status": True})

    return JsonResponse({"status": False, "error_msg": "信息未填写完整"})


def test(request):
    if request.method == 'POST':
        params = request.POST.get('params')
        return JsonResponse({"status": True})
    return render(request, 'api_define_add2.html')


def api_define_request_test(request):
    content_type = {0: 'text/html', 1: "application/json", 2: "text/plain", 3: "text/javascript", 4: "text/xml"}
    api_method = request.POST['api_method']
    api_url = request.POST['api_url']
    api_params = json.loads(request.POST['api_params'])
    api_headers = json.loads(request.POST['api_headers'])
    body_choice = int(request.POST['body_choice'])
    try:
        api_body = json.loads(request.POST['api_body'])
    except Exception as e:
        return JsonResponse({"status": False, "error_msg": "参数错误"})
    try:

        if api_method == "GET":
            rep = requests.get(url=api_url, headers=api_headers, params=api_params)
            rep_status_code = rep.status_code
            rep_json_data = rep.text
            rep_reason = rep.reason
            rep_time = int(rep.elapsed.total_seconds() * 1000)
            return JsonResponse({"status": True, "rep_status_code": rep_status_code, "rep_json_data": rep_json_data,
                                 "rep_reason": rep_reason, "rep_time": rep_time})

        if api_method == "POST":
            if body_choice == 1:
                api_headers['Content-Type'] = 'application/x-www-form-urlencoded'
            if body_choice == 2:
                rep = requests.post(url=api_url, headers=api_headers, params=api_params, json=api_body)
            else:
                rep = requests.post(url=api_url, headers=api_headers, params=api_params, data=api_body)
            rep_status_code = rep.status_code
            rep_json_data = rep.json()
            rep_reason = rep.reason
            rep_time = int(rep.elapsed.total_seconds() * 1000)
            return JsonResponse({"status": True, "rep_status_code": rep_status_code, "rep_json_data": rep_json_data,
                                 "rep_reason": rep_reason, "rep_time": rep_time})
    except requests.exceptions.MissingSchema as e:
        return JsonResponse({"status": False, "error_msg": "数据请求失败"})


def api_save_case(request):
    is_assert = request.POST['is_assert']
    api_id = request.POST['api_id']
    api_name = request.POST['api_name']
    api_method = request.POST['api_method']
    api_url = request.POST['api_url']
    api_params = request.POST['api_params']
    api_headers = request.POST['api_headers']
    body_choice = request.POST['body_choice']
    api_body = request.POST['api_body']
    assert_choice = request.POST['assert_choice']
    api_assert = request.POST['api_assert']
    if (api_name and api_method and api_url):
        api_case = ApiCase(name=api_name, api_define_id=api_id, interface=api_url,
                           method=api_method, params=api_params,
                           headers=api_headers,
                           body_type=body_choice, body=api_body, is_assert=is_assert,
                           assert_type=assert_choice, assert_body=api_assert,
                           )
        api_case.save()
        return JsonResponse({"status": True})


def api_case_list(request):
    try:
        page = request.GET.get('page', 1)
    except PageNotAnInteger:
        page = 1
    nums = request.GET.get('nums', None)
    search_text = request.GET.get('Search', '')
    search_dict = {}
    projects_list = Projects.objects.all().order_by('-create_time')
    is_project = int(request.COOKIES['Project'])
    if search_text:
        search_dict['name__contains'] = search_text
    search_dict['api_define__module__project'] = is_project
    api_cases_list = ApiCase.objects.filter(**search_dict).order_by('api_define', '-create_time')
    content = Pagination(api_cases_list, search_text, page, nums).per_page()
    content['projects_list'] = projects_list
    content['is_project'] = is_project
    return render(request, 'api_case_list.html', content)


def api_case_del(request):
    api_case_id = request.POST['api_case_id']
    ApiCase.objects.filter(id=api_case_id).delete()
    return JsonResponse({"status": True})


def api_case_edit(request):
    if request.method == 'GET':
        projects_list = Projects.objects.all().order_by('-create_time')
        is_project = int(request.COOKIES['Project'])
        api_case_id = request.GET.get('api_case_id')
        api_case = ApiCase.objects.get(id=api_case_id)
        params = json.loads(api_case.params)
        headers = json.loads(api_case.headers)
        content = {
            'api_case': api_case,
            "params": params,
            "headers": headers,
            "projects_list": projects_list,
            "is_project": is_project,

        }
        return render(request, 'api_case_edit.html', content)
    is_assert = request.POST['is_assert']
    api_id = request.POST['api_id']
    api_case_name = request.POST['api_case_name']
    api_params = request.POST['api_params']
    api_headers = request.POST['api_headers']
    body_choice = request.POST['body_choice']
    api_body = request.POST['api_body']
    assert_choice = request.POST['assert_choice']
    api_assert = request.POST['api_assert']
    if (api_case_name):
        ApiCase.objects.filter(id=api_id).update(name=api_case_name,
                                                 params=api_params,
                                                 headers=api_headers,
                                                 body_type=body_choice, body=api_body,
                                                 assert_type=assert_choice, assert_body=api_assert,
                                                 is_assert=is_assert)
        return JsonResponse({"status": True})

    return JsonResponse({"status": False, "error_msg": "信息未填写完整"})


def api_case_auto(request):
    try:
        page = request.GET.get('page', 1)
    except PageNotAnInteger:
        page = 1
    nums = request.GET.get('nums', None)
    search_text = request.GET.get('Search', '')
    search_dict = {}

    projects_list = Projects.objects.all().order_by('-create_time')
    is_project = int(request.COOKIES['Project'])
    if is_project:
        project_id = projects_list.get(id=is_project)
        api_auto_set = project_id.apiautotest_set.all()
        api_auto_id_list = [api_auto.id for api_auto in api_auto_set]
        search_dict['id__in'] = api_auto_id_list
    if search_text:
        search_dict['name__contains'] = search_text
    api_case_list = ApiAutoTest.objects.filter(**search_dict).order_by('-create_time')
    content = Pagination(api_case_list, search_text, page, nums).per_page()
    content['projects_list'] = projects_list
    content['is_project'] = is_project

    return render(request, 'api_case_auto_list.html', content)


def api_auto_del(request):
    api_auto_id = request.POST['api_auto_id']
    ApiAutoTest.objects.filter(id=api_auto_id).delete()
    return JsonResponse({"status": True})


def api_auto_copy(request):
    api_auto_id = request.POST['api_auto_id']
    api_auto_test = ApiAutoTest.objects.get(id=api_auto_id)
    auto_copy = copy.deepcopy(api_auto_test)
    auto_copy.pk = None
    auto_copy.name = api_auto_test.name + "(复制)"
    auto_copy.save()
    return JsonResponse({"status": True})

def api_auto_add(request):
    user = request.user
    api_case_name = request.POST['api_case_name']
    api_case_priority = request.POST['api_case_priority']
    api_case_describe = request.POST['api_case_describe']
    api_project = int(request.POST['api_project'])
    if api_case_name:
        api_auto = ApiAutoTest(name=api_case_name, priority=api_case_priority, describe=api_case_describe, creator=user,
                               project_id=api_project, cases='[]')
        api_auto.save()
        return JsonResponse({"status": True})
    return JsonResponse({"status": False})


def api_auto_edit(request):
    if request.method == "GET":
        api_auto_id = request.GET.get('api_auto_id')
        project_id = request.GET.get('project_id')
        api_auto = ApiAutoTest.objects.get(id=api_auto_id)
        case_list = []
        projects_list = Projects.objects.all().order_by('-create_time')
        is_project = int(request.COOKIES['Project'])
        if api_auto.cases:
            for case in json.loads(api_auto.cases):
                case_dict = {}

                try:
                    case = ApiCase.objects.get(id=case)
                    case_dict['id'] = case.id
                    case_dict['method'] = case.get_method_display()
                    case_dict['case_name'] = case.name
                    case_dict['api_name'] = case.api_define
                    case_list.append(case_dict)
                except Exception:
                    continue
        return render(request, 'api_auto_edit.html',
                      {"api_auto": api_auto, "project_id": project_id, "case_list": case_list,
                       "projects_list": projects_list, "is_project": is_project})
    api_auto_id = request.POST['api_auto_id']
    api_case_name = request.POST['api_case_name']
    api_case_priority = request.POST['api_case_priority']
    api_case_describe = request.POST['api_case_describe']
    api_auto = ApiAutoTest.objects.get(id=api_auto_id)
    api_auto.name = api_case_name
    api_auto.priority = api_case_priority
    api_auto.describe = api_case_describe
    api_auto.save()
    return JsonResponse({"status": True})


def api_step_save(request):
    step_id = request.POST['step_id']
    api_id = request.POST['api_id']
    user = request.user
    case = ApiAutoTest.objects.get(id=api_id)
    case.cases = step_id
    case.u_creator = str(user)
    case.save()
    return JsonResponse({"status": True})


def api_case_run(request):
    api_auto_id = request.POST['api_auto_id']
    user = request.user
    return JsonResponse(AutoThread(api_auto_id, user).run_cases())


from multiprocessing import Process


class AutoThread:
    def __init__(self, api_auto_id, user):
        self.api_auto_id = api_auto_id
        self.user = user

    def run_cases(self):
        api_auto = ApiAutoTest.objects.get(id=self.api_auto_id)
        # CaseTemporary.objects.all().delete()
        test_data = {}
        for case_id in json.loads(api_auto.cases):
            try:
                api_case = ApiCase.objects.get(id=case_id)

                case_temporary = CaseTemporary(name=api_case.name, interface=api_case.interface,
                                               method=api_case.method, params=api_case.params,
                                               headers=api_case.headers,
                                               body_type=api_case.body_type, body=api_case.body,
                                               is_assert=api_case.is_assert,
                                               assert_type=api_case.assert_type, assert_body=api_case.assert_body,
                                               )
                case_temporary.save()
                if api_case.body == '':
                    api_case.body = "{}"
                test_data[api_case.name] = {
                    "method": api_case.get_method_display(),
                    "url": api_case.interface,
                    "headers": json.loads(api_case.headers),
                    "params": json.loads(api_case.params),
                    "body_type": api_case.body_type,
                    "body": json.loads(api_case.body),
                    "is_assert": api_case.is_assert,
                    "assert_type": api_case.assert_type,
                    "assert_body": api_case.assert_body
                }
            except:
                continue
        if test_data:
            case_data = json.dumps(test_data, ensure_ascii=False, indent=1)
            filepath = CURRENT_PATH + os.sep + 'templates\json\case_data.json'
            with open(filepath, 'w', encoding='utf-8') as f:
                f.write(case_data)
                f.close()
            test_report = TestReports(title=api_auto.name, status=0, api_auto=api_auto, tester=self.user)
            test_report.save()
            # run_suite(test_report.id, test_report.title)
            # dance_process = Process(target=run_suite, args=(test_report.id, test_report.title))
            # dance_process.start()
            run_cmd = "python " + CURRENT_PATH + r"\run_cases.py"
            os.system(run_cmd)
            # t1 = threading.Thread(target=run_suite, args=(test_report.id, test_report.title))
            # t1.start()
            t = ThreadTimer(1, AutoThread.wait_report_status, args=(test_report.id,))
            t.start()
            t.join()
            return t.get_result()
        else:
            return {"status": False, "error_msg": "检测到无用例，无需执行"}

    @classmethod
    def wait_report_status(cls, report_id):
        test_report = TestReports.objects.get(id=report_id)
        if test_report.status == 1:
            return {"status": True, "url": test_report.report_url}
        sleep(0.5)
        AutoThread.wait_report_status(report_id)


def case_show_report(request):
    url = request.GET['url']
    return render(request, 'report/' + url)


def get_case_tree(request):
    project_id = request.GET.get('project_id')
    modules = Modules.objects.filter(project=project_id)
    api_defines_list = []
    for module in modules:
        api_defines = ApiDefine.objects.filter(module_id=module.id).order_by('-create_time')

        for api_define in api_defines:
            name = api_define.get_method_display() + '    ' + api_define.name + '    ' + api_define.interface
            api_define_data = {
                "name": name,
                "isParent": True,
            }
            api_cases = ApiCase.objects.filter(api_define_id=api_define.id)
            api_cases_list = []
            for api_case in api_cases:
                api_case_data = {
                    "api_define_name": api_define.name,
                    "name": api_case.name,
                    "isParent": False,
                    "id": api_case.id,
                    "method": api_case.get_method_display(),
                    "url": api_case.interface
                }
                api_cases_list.append(api_case_data)
            api_define_data['children'] = api_cases_list
            api_defines_list.append(api_define_data)
    return JsonResponse({"status": 10200, "data": api_defines_list})


EXTEND_DIR = BASE_PATH


def api_run_case(request):
    api_define_id = request.GET.get('api_define_id')
    api_define = ApiDefine.objects.get(id=api_define_id)
    test_data = {}
    test_data[api_define.name] = {
        "url": api_define.interface,
        "params": api_define.params,
        "headers": api_define.headers,
        "body_type": api_define.get_body_type_display(),
        "assert_type": api_define.get_assert_type_display(),
        "assert_body": api_define.assert_body,
        "api_body": api_define.body

    }
    json_data = json.dumps(test_data)
    with open(EXTEND_DIR + 'case_data.json', 'w', encoding='utf-8') as f:
        f.write(json_data)

    return HttpResponse('ok')
    # if api_define.get_method_display() == "GET":

